using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;
using needle.UI.Controls.Flat.Utilities.Drawing;
using needle.UI.Controls.Flat.Utilities.CoreHelpers;
using needle.UI.Controls.Flat.Windows.Forms.Helpers;

namespace needle.UI.Controls.Flat.Windows.Forms
{
	[System.ComponentModel.ToolboxItem(true)]
	public class SpinEdit : ControlBase, IFlashabledControl
	{		
		private TextBoxBase m_pTextBox;
		private System.ComponentModel.IContainer components = null;
		private LeftRight m_ButtonsAlign = LeftRight.Right;
		private int m_ButtonWidth = 16;
		private Icon m_UpButtonIcon = null;
		private Icon m_DownButtonIcon = null;
		private bool m_ReadOnly = false;
		private bool m_ShowErrorProvider = true; 
		private System.Windows.Forms.Timer countTimer = null;

		bool mouseDown = false;
		bool keySumDown = false;
		bool keyMinusDown = false;

		//Style Neo, default!!
		private Color m_TextColor = Color.Black;
		private Color m_EditDisabledColor = Color.FromArgb(238, 238, 225);
		private Color m_EditReadOnlyColor = Color.FromArgb(238, 238, 225);
		private Color m_EditFocusedColor = Color.White;
		private Color m_EditColor = Color.FromArgb(242, 242, 228);
		private Color m_NegativeNumberColor = Color.Black;
		private Color m_FlashColor = Color.FromArgb(170, 170, 221);
		private Color m_ButtonColor = Color.FromArgb(242, 242, 228);
		private Color m_ButtonHotColor = Color.FromArgb(231, 231, 214);
		private Color m_ButtonPressedColor = Color.FromArgb(222, 217, 207);
		private Color m_ButtonBorderColor = Color.FromArgb(222, 217, 207);
		private Color m_ButtonBorderHotColor = Color.FromArgb(222, 217, 207);

		public event ErrorOcurredEventHandler ErrorOcurred = null;
		
		#region Constructors
		public SpinEdit()
		{
			InitializeComponent();
			m_pTextBox.LostFocus        += new System.EventHandler(this.m_pTextBox_OnLostFocus);
			m_pTextBox.GotFocus         += new System.EventHandler(this.m_pTextBox_OnGotFocus);
			m_pTextBox.NumberOcurred    += new NumberOcurredEventHandler(this.m_pTextBox_NumberOcurred);
			
			countTimer = new System.Windows.Forms.Timer();
			countTimer.Enabled = false;
			countTimer.Tick   += new System.EventHandler(OnTimerTick);
			
			m_UpButtonIcon     = GraphicsUtils.LoadIcon("up.ico");
			m_DownButtonIcon   = GraphicsUtils.LoadIcon("down.ico");
			m_pTextBox.Mask    = EditMask.Numeric; 
			this.m_pTextBox.DecimalPlaces = 0;
		}
		#endregion

		#region Dispose
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null){
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}
		#endregion

		#region Component Designer generated code
		private void InitializeComponent()
		{
			this.m_pTextBox = new needle.UI.Controls.Flat.Windows.Forms.TextBoxBase();
			this.SuspendLayout();
			// 
			// m_pTextBox
			// 
			this.m_pTextBox.Anchor = (System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right);
			this.m_pTextBox.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(242)), ((System.Byte)(242)), ((System.Byte)(228)));
			this.m_pTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
			this.m_pTextBox.DecimalPlaces = 2;
			this.m_pTextBox.DecMaxValue = 999999999;
			this.m_pTextBox.DecMinValue = -999999999;
			this.m_pTextBox.Location = new System.Drawing.Point(3, 2);
			this.m_pTextBox.Mask = needle.UI.Controls.Flat.Windows.Forms.EditMask.Custom;
			this.m_pTextBox.Name = "m_pTextBox";
			this.m_pTextBox.NotAcceptsChars = "";
			this.m_pTextBox.Required = false;
			this.m_pTextBox.Size = new System.Drawing.Size(95, 13);
			this.m_pTextBox.TabIndex = 0;
			this.m_pTextBox.Text = "";
			this.m_pTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.m_pTextBox_KeyDown);
			this.m_pTextBox.ErrorOcurred += new needle.UI.Controls.Flat.Windows.Forms.ErrorOcurredEventHandler(this.m_pTextBox_ErrorOcurred);
			this.m_pTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.m_pTextBox_KeyUp);
			this.m_pTextBox.NumberOcurred += new needle.UI.Controls.Flat.Windows.Forms.NumberOcurredEventHandler(this.m_pTextBox_NumberOcurred);
			this.m_pTextBox.TextChanged += new System.EventHandler(this.m_pTextBox_TextChanged);
			// 
			// SpinEdit
			// 
			this.Controls.AddRange(new System.Windows.Forms.Control[] {
																		  this.m_pTextBox});
			this.Name = "SpinEdit";
			this.Size = new System.Drawing.Size(118, 19);
			this.Load += new System.EventHandler(this.EnterpriseSpinEdit_Load);
			this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.EnterpriseSpinEdit_MouseUp);
			this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.EnterpriseSpinEdit_MouseMove);
			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.EnterpriseSpinEdit_MouseDown);
			this.ResumeLayout(false);

		}
		#endregion

		#region Events handlers
		
		private void OnTimerTick(object sender, EventArgs e)
		{
			if (this.mouseDown)
			{
				Rectangle upButtonRect   = GetUpButtonRect();
				Rectangle downButtonRect = GetDownButtonRect();

				if(upButtonRect.Contains(this.PointToClient(Control.MousePosition)))
				{
					this.ChangeValue(true);
				}
				else if (downButtonRect.Contains(this.PointToClient(Control.MousePosition)))
				{
					this.ChangeValue(false);
				}
			}
			else if (this.keySumDown)
			{
				this.ChangeValue(true);
			}
			else if (this.keyMinusDown)
			{
				this.ChangeValue(false);
			}
		}
		
		private void EnterpriseSpinEdit_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if(this.Enabled && !this.ReadOnly && e.Button == MouseButtons.Left && IsMouseInButtonRect())
			{
				this.mouseDown = false;
				this.countTimer.Enabled = false;
			}
		}

		private void EnterpriseSpinEdit_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if(this.Enabled && !this.ReadOnly && e.Button == MouseButtons.Left && IsMouseInButtonRect())
			{
				if(IsMouseInButtonRect()) this.Invalidate(false);
				this.mouseDown = true;
				this.OnTimerTick(this, e);
				this.countTimer.Enabled = true;
			}
		}

		private void EnterpriseSpinEdit_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if(IsMouseInButtonRect()){
				this.Invalidate(false);
			}
		}

		private void m_pTextBox_OnLostFocus(object sender, System.EventArgs e)
		{
			this.BackColor = this.Style!=null? this.Style.InteliEditColor(this.m_pTextBox.ReadOnly,this.Enabled):
				StyleGuide.InteliEditColor(this.m_pTextBox.ReadOnly,this.Enabled,this.m_EditColor, this.m_EditReadOnlyColor, this.m_EditDisabledColor);
		}

		private void m_pTextBox_OnGotFocus(object sender, System.EventArgs e)
		{
			this.BackColor   = this.m_EditFocusedColor;
		}

		private void m_pTextBox_TextChanged(object sender, System.EventArgs e)
		{
			base.OnTextChanged(new System.EventArgs());
		}

		private void m_pTextBox_NumberOcurred(object sender, NumberOcurredEventArgs e)
		{
			e.NegativeNumberColor = this.m_NegativeNumberColor;
			e.PositiveNumberColor = this.m_TextColor;
		}

		private void m_pTextBox_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Up)
			{
				this.keySumDown = false;
				this.countTimer.Enabled = false;
			}
			else if (e.KeyCode == Keys.Down)
			{
				this.keyMinusDown = false;
				this.countTimer.Enabled = false;
			}
		}

		private void m_pTextBox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Up)
			{
				this.keySumDown = true;
				this.OnTimerTick(this, e);
				this.countTimer.Enabled = true;
			}
			else if (e.KeyCode == Keys.Down)
			{
				this.keyMinusDown = true;
				this.OnTimerTick(this, e);
				this.countTimer.Enabled = true;
			}
		}

		private void EnterpriseSpinEdit_Load(object sender, System.EventArgs e)
		{
			m_pTextBox.Text = this.DecValue.ToString(CultureInfo.CurrentCulture);
		}

		private void m_pTextBox_ErrorOcurred(object sender, ErrorOcurredEventArgs e)
		{
			if (e.Message.Length > 0)
			{
				if (this.ErrorOcurred != null)
				{
					ErrorOcurredEventArgs oArg = new ErrorOcurredEventArgs(e.Message);
					ErrorOcurred(this,oArg); 
				}
			}
			//
			if (m_ShowErrorProvider) 
				base.Errors.SetError(this, e.Message);
		}

		#endregion

		#region Virtuals

		protected virtual void OnButtonPressed() 
		{	
			System.EventArgs oArg = new System.EventArgs();
		}

		#endregion

		#region Overrides

		protected override void DrawControl(Graphics g,bool hot)
		{
			Point mPoint = Control.MousePosition;
					
			bool border_hot = hot;
			
			
			GraphicsUtils.DrawBorder(g,base.BorderColor,base.BorderHotColor, this.ClientRectangle,border_hot);

			Rectangle upButtonRect   = GetUpButtonRect();
			Rectangle downButtonRect = GetDownButtonRect();

			bool btn_hot         = (IsMouseInButtonRect() && this.Enabled);
			bool btnUppressed   = IsMouseInButtonRect() && Control.MouseButtons == MouseButtons.Left && upButtonRect.Contains(this.PointToClient(mPoint));
			bool btnDown_pressed = IsMouseInButtonRect() && Control.MouseButtons == MouseButtons.Left && downButtonRect.Contains(this.PointToClient(mPoint));;

			
			GraphicsUtils.DrawButton(g,this.m_ButtonColor,
				this.m_ButtonHotColor,
				this.m_ButtonPressedColor,
				this.m_ButtonBorderColor,
				this.m_ButtonBorderHotColor,upButtonRect,border_hot,btn_hot,btnUppressed);

			GraphicsUtils.DrawButton(g,this.m_ButtonColor,
				this.m_ButtonHotColor,
				this.m_ButtonPressedColor,
				this.m_ButtonBorderColor,
				this.m_ButtonBorderHotColor,downButtonRect,border_hot,btn_hot,btnDown_pressed);
			

			if(m_UpButtonIcon != null && m_DownButtonIcon != null){
			
				if(m_ButtonWidth < this.Height + 2){					
					upButtonRect   = new Rectangle(upButtonRect.X,upButtonRect.Y + (upButtonRect.Height - upButtonRect.Width)/2 + 1,upButtonRect.Width,upButtonRect.Height);
					downButtonRect = new Rectangle(downButtonRect.X,downButtonRect.Y + (downButtonRect.Height - downButtonRect.Width)/2 + 1,downButtonRect.Width,downButtonRect.Height);
				}				
				
				downButtonRect.Location = new Point(downButtonRect.X,downButtonRect.Y - 1);
				downButtonRect.Height   = downButtonRect.Width;

				upButtonRect.Location = new Point(upButtonRect.X,upButtonRect.Y - 2);
				upButtonRect.Height   = upButtonRect.Width;

				DrawHelpers.DrawIcon(g,m_UpButtonIcon,upButtonRect,false,btnUppressed);
				DrawHelpers.DrawIcon(g,m_DownButtonIcon,downButtonRect,false,btnDown_pressed);
			}
		}

		protected override void OnEnabledChanged(System.EventArgs e)
		{
			base.OnEnabledChanged(e);

			if (!this.Enabled) this.countTimer.Enabled = false;

			this.BackColor = this.Style!=null? this.Style.InteliEditColor(this.m_pTextBox.ReadOnly,this.Enabled):
				StyleGuide.InteliEditColor(this.m_pTextBox.ReadOnly,this.Enabled,this.m_EditColor, this.m_EditReadOnlyColor, this.m_EditDisabledColor);
		}

		protected override void OnStyleChanged(object sender, StyleEventArgs args)
		{
			base.OnStyleChanged(sender, args);

			if (args.PropertyName == "FlashColor") {this.FlashColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "TextColor") {this.TextColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditColor") {this.EditColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditFocusedColor") {this.EditFocusedColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditReadOnlyColor") {this.EditReadOnlyColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditDisabledColor") {this.EditDisabledColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditButtonColor") {this.ButtonColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditButtonHotColor") {this.ButtonHotColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditButtonPressedColor") {this.ButtonPressedColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "NegativeNumberColor") {this.NegativeNumberColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "ButtonBorderColor") {this.BorderColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "ButtonBorderHotColor") {this.BorderHotColor = (Color)args.PropertyValue;}

			this.BackColor = this.Style!=null? this.Style.InteliEditColor(this.m_pTextBox.ReadOnly,this.Enabled):
				StyleGuide.InteliEditColor(this.m_pTextBox.ReadOnly,this.Enabled,this.m_EditColor, this.m_EditReadOnlyColor, this.m_EditDisabledColor);
			
			this.Invalidate(true);
		}

		protected override void OnPlansOfColorsChanged(object sender, PlansOfColorsChangedEventArgs args)
		{
			base.OnPlansOfColorsChanged(sender, args);

			if (this.Style!=null)
			{
				this.FlashColor = this.Style.FlashColor;
				this.EditColor = this.Style.EditColor;
				this.EditFocusedColor = this.Style.EditFocusedColor;
				this.EditReadOnlyColor = this.Style.EditReadOnlyColor;
				this.EditDisabledColor = this.Style.EditDisabledColor;
				this.TextColor = this.Style.TextColor;
				this.ButtonColor = this.Style.EditButtonColor;
				this.ButtonHotColor = this.Style.EditButtonHotColor;
				this.ButtonPressedColor = this.Style.EditButtonPressedColor;
				this.NegativeNumberColor = this.Style.NegativeNumberColor;
				this.ButtonBorderColor = this.Style.BorderColor;
				this.ButtonBorderHotColor = this.Style.BorderHotColor;

				this.BackColor = this.Style!=null? this.Style.InteliEditColor(this.m_pTextBox.ReadOnly,this.Enabled):
					StyleGuide.InteliEditColor(this.m_pTextBox.ReadOnly,this.Enabled,this.m_EditColor, this.m_EditReadOnlyColor, this.m_EditDisabledColor);
			}

			this.Invalidate(true);
		}

		#endregion

		#region Internal helpers

		private void ThreadFlashControl()
		{
			for (int i=1; i<=8;i++)
			{
				if(this.m_pTextBox.BackColor == this.EditColor)
				{
					this.m_pTextBox.BackColor = this.FlashColor;
				}
				else
				{
					this.m_pTextBox.BackColor = this.EditColor;
				}
				Thread.Sleep(150);
			}

			this.m_pTextBox.BackColor = this.EditColor;
		}

		private void ChangeValue(bool ChangeUp)
		{
			if (ChangeUp)
			{
				double val = CommonHelpers.StringToDouble(this.Text);
				val++;
				if(val <= this.DecMaxValue)
				{
					this.Text = val.ToString(CultureInfo.CurrentCulture);
				}
			}
			else
			{
				double val = CommonHelpers.StringToDouble(this.Text);
				val--;
				if(val >= this.DecMinValue)
				{
					this.Text = val.ToString(CultureInfo.CurrentCulture);
				}
			}
		}

		private Rectangle GetUpButtonRect()
		{
			Rectangle rectButton = GetButtonsRect();
			Rectangle retVal = new Rectangle(rectButton.X,rectButton.Y,rectButton.Width,rectButton.Height/2+1);
			return retVal;
		}

		private Rectangle GetDownButtonRect()
		{
			Rectangle rectButton = GetButtonsRect();
			Rectangle retVal = new Rectangle(rectButton.X,rectButton.Height/2+2,rectButton.Width,rectButton.Height/2);
			return retVal;
		}

		private Rectangle GetButtonsRect()
		{
			if(m_ButtonsAlign == LeftRight.Right)
			{
				Rectangle rectButton = new Rectangle(this.Width - m_ButtonWidth,1,m_ButtonWidth - 1,this.Height - 2);
				return rectButton;
			}
			else
			{
				Rectangle rectButton = new Rectangle(1,1,m_ButtonWidth - 1,this.Height - 2);
				return rectButton;
			}
		}

		private bool IsMouseInButtonRect()
		{
			Rectangle rectButton = GetButtonsRect();
			Point mPos = Control.MousePosition;
			if(rectButton.Contains(this.PointToClient(mPos)))
			{
				return true;
			}
			else
			{
				return false;
			}
		}

		#endregion

		#region Properties

		[Browsable(false),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public new Color BackColor
		{
			get{ return base.BackColor; }

			set
			{
				base.BackColor      = value;
				if (m_pTextBox!=null) m_pTextBox.BackColor = value;
			}
		}

		[Browsable(false)]
		public override Color ForeColor
		{
			get{ return base.ForeColor; }

			set
			{
				base.ForeColor       = value;
				m_pTextBox.ForeColor = value;
			}
		}

		[Category("Style")]
		public Color TextColor
		{
			get {return m_TextColor;}
			set 
			{
				m_TextColor = value;
				this.m_pTextBox.ForeColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color FlashColor
		{
			get {return m_FlashColor;}
			set 
			{
				m_FlashColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color EditColor
		{
			get {return m_EditColor;}
			set 
			{
				m_EditColor = value;
				this.BackColor = value;
				this.m_pTextBox.BackColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color NegativeNumberColor
		{
			get {return m_NegativeNumberColor;}
			set 
			{
				m_NegativeNumberColor = value;
			}
		}

		[Category("Style")]
		public Color EditFocusedColor
		{
			get {return m_EditFocusedColor;}
			set 
			{
				m_EditFocusedColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color EditReadOnlyColor
		{
			get {return m_EditReadOnlyColor;}
			set 
			{
				m_EditReadOnlyColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color EditDisabledColor
		{
			get {return m_EditDisabledColor;}
			set 
			{
				m_EditDisabledColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color ButtonColor
		{
			get {return m_ButtonColor;}
			set 
			{
				m_ButtonColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color ButtonHotColor
		{
			get {return m_ButtonHotColor;}
			set 
			{
				m_ButtonHotColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color ButtonPressedColor
		{
			get {return m_ButtonPressedColor;}
			set 
			{
				m_ButtonPressedColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color ButtonBorderColor
		{
			get {return m_ButtonBorderColor;}
			set 
			{
				m_ButtonBorderColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color ButtonBorderHotColor
		{
			get {return m_ButtonBorderHotColor;}
			set 
			{
				m_ButtonBorderHotColor = value;
				this.Invalidate();
			}
		}

		[Category("Appearance")]
		public LeftRight ButtonsAlign
		{
			get{ return m_ButtonsAlign; }

			set{ 
				m_ButtonsAlign = value;
				
				if(value == LeftRight.Left){
					m_pTextBox.Left = this.Width - m_pTextBox.Width - 3;
				}
				else{
					m_pTextBox.Left = 3;
				}

				Invalidate(false);
			}
		}

		[Category("Behavior")]
		public bool ReadOnly
		{
			get{ return m_ReadOnly; }

			set{ 
				m_ReadOnly          = value;
				m_pTextBox.ReadOnly = value;
			}
		}

		[Category("Behavior")]
		public int MaxLength
		{
			get{ return m_pTextBox.MaxLength; }

			set{ m_pTextBox.MaxLength = value; }
		}

		[Browsable(true),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
		Category("Appearance"),
		Bindable(true)]
		public override string Text
		{
			get{ return m_pTextBox.Text; }

			set{ m_pTextBox.Text = value; }
		}

		[Category("Behavior")]
		public HorizontalAlignment TextAlign
		{
			get{ return m_pTextBox.TextAlign; }

			set{ m_pTextBox.TextAlign = value; }
		}

		[Category("Behavior")]
		public double DecValue
		{
			get{return m_pTextBox.DoubleValue;}
			set{m_pTextBox.DoubleValue = value;}
		}

		[Category("Behavior")]
		public int DecMinValue
		{
			get{ return m_pTextBox.DecMinValue; }

			set{ m_pTextBox.DecMinValue = value; }
		}

		[Category("Behavior")]
		public int DecMaxValue
		{
			get{ return m_pTextBox.DecMaxValue; }

			set{ m_pTextBox.DecMaxValue = value; }
		}

		[Category("Behavior")]
		public bool Required
		{
			get
			{ 
				return m_pTextBox.Required; 
			}
			set
			{
				m_pTextBox.Required = value;
			}
		}

		[Category("Behavior")]
		public bool ShowErrorProvider
		{
			get{ return m_ShowErrorProvider; }
			set{ m_ShowErrorProvider = value; }
		}

		#endregion

		#region IFlashabledControl

		public void FlashControl()
		{
			Thread m_Thread = new Thread(new ThreadStart(ThreadFlashControl));
			m_Thread.Start();
		}
		
		#endregion
	}
}
